/*
 * DevicesLed.c
 *
 *      Author: Honrun
 */

#include "n32g031.h"
#include "DevicesSoftTimer.h"
#include "DevicesLed.h"




static LedInfoType st_typeLedInfo = {0};

/* 周期调用计数（调用频率为10k） */
volatile static uint32_t st_uiLedTickCnt = 0;
/* 呼吸档位 */
volatile static int16_t st_sGrade = 0;


SoftTimerTypeDef g_typeSoftTimerLedHanle = {0};


void vSoftTimerLedCallbackFunction(void *pvHandle)
{
    (void)pvHandle;

    vLedMachine();
}

void vLedInit(void)
{
    GPIO_InitType GPIO_InitStructure = {0};

    /* -1- Enable GPIOx Clock (to be able to program the configuration registers) */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_GPIOF, ENABLE);


    st_typeLedInfo.white.periph = LED_WHITE_GPIO_Port;
    st_typeLedInfo.white.pin = LED_WHITE_Pin;
    st_typeLedInfo.white.channel = LED_WHITE;

    st_typeLedInfo.blue.periph = LED_BLUE_GPIO_Port;
    st_typeLedInfo.blue.pin = LED_BLUE_Pin;
    st_typeLedInfo.blue.channel = LED_BLUE;

    st_typeLedInfo.bag.periph = LED_BAG_GPIO_Port;
    st_typeLedInfo.bag.pin = LED_BAG_Pin;
    st_typeLedInfo.bag.channel = LED_BAG;

    st_typeLedInfo.exist.periph = LED_EXIST_GPIO_Port;
    st_typeLedInfo.exist.pin = LED_EXIST_Pin;
    st_typeLedInfo.exist.channel = LED_EXIST;


    /* -2- Configure GPIOx_PIN in output push-pull mode */
    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.Pin = st_typeLedInfo.white.pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitPeripheral(st_typeLedInfo.white.periph, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = st_typeLedInfo.blue.pin;
    GPIO_InitPeripheral(st_typeLedInfo.blue.periph, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = st_typeLedInfo.bag.pin;
    GPIO_InitPeripheral(st_typeLedInfo.bag.periph, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = st_typeLedInfo.exist.pin;
    GPIO_InitPeripheral(st_typeLedInfo.exist.periph, &GPIO_InitStructure);

    vLedOpen(LED_ALL);


    /* 软件定时器周期调用 */
    cSoftTimerCreateMs(&g_typeSoftTimerLedHanle, LED_PERIODIC_TIME, softTimerOpen | softTimerCircular, vSoftTimerLedCallbackFunction);

    vLedSetStatus(LED_ALL, LED_FLASH_SLOW_CIRCULAR, 10);
}

void vLedOpen(uint16_t usChannel)
{
    if(usChannel & LED_WHITE)
        GPIO_SetBits(LED_WHITE_GPIO_Port, LED_WHITE_Pin);
    if(usChannel & LED_BLUE)
        GPIO_SetBits(LED_BLUE_GPIO_Port, LED_BLUE_Pin);
    if(usChannel & LED_BAG)
        GPIO_SetBits(LED_BAG_GPIO_Port, LED_BAG_Pin);
    if(usChannel & LED_EXIST)
        GPIO_SetBits(LED_EXIST_GPIO_Port, LED_EXIST_Pin);
}

void vLedClose(uint16_t usChannel)
{
    if(usChannel & LED_WHITE)
        GPIO_ResetBits(LED_WHITE_GPIO_Port, LED_WHITE_Pin);
    if(usChannel & LED_BLUE)
        GPIO_ResetBits(LED_BLUE_GPIO_Port, LED_BLUE_Pin);
    if(usChannel & LED_BAG)
        GPIO_ResetBits(LED_BAG_GPIO_Port, LED_BAG_Pin);
    if(usChannel & LED_EXIST)
        GPIO_ResetBits(LED_EXIST_GPIO_Port, LED_EXIST_Pin);
}

void vLedRevesal(uint16_t usChannel)
{
    if(usChannel & LED_WHITE)
        GPIO_TogglePin(LED_WHITE_GPIO_Port, LED_WHITE_Pin);
    if(usChannel & LED_BLUE)
        GPIO_TogglePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin);
    if(usChannel & LED_BAG)
        GPIO_TogglePin(LED_BAG_GPIO_Port, LED_BAG_Pin);
    if(usChannel & LED_EXIST)
        GPIO_TogglePin(LED_EXIST_GPIO_Port, LED_EXIST_Pin);
}

void vLedDuty(uint16_t usChannel, float fDuty)
{
}

/*
 * Return:      void
 * Parameters:  usChannel: LED通道; usChannel: 状态; usChannel: 闪烁次数/或者占空比;
 * Description: 设置LED状态
 */
void vLedSetStatus(uint16_t usChannel, LedStateEnum enumStatus, uint8_t ucFlashCnt_or_Duty)
{
    int8_t cFlashFrequency = 0;

    cFlashFrequency = ((enumStatus >= LED_FLASH_SLOW_CIRCULAR) && (enumStatus <= LED_FLASH_SLOW_DISABLE_CNT)) ?  (LED_FLASH_SLOW_TIME / LED_PERIODIC_TIME) : (LED_FLASH_FAST_TIME / LED_PERIODIC_TIME);

    if(usChannel & LED_WHITE)
    {
        st_typeLedInfo.white.state = enumStatus;
        st_typeLedInfo.white.flashCnt = ucFlashCnt_or_Duty * 2 + 1;
        st_typeLedInfo.white.flashFrequency = cFlashFrequency;
        st_typeLedInfo.white.duty = ucFlashCnt_or_Duty % 101;
    }
    if(usChannel & LED_BLUE)
    {
        st_typeLedInfo.blue.state = enumStatus;
        st_typeLedInfo.blue.flashCnt = ucFlashCnt_or_Duty * 2 + 1;
        st_typeLedInfo.blue.flashFrequency = cFlashFrequency;
        st_typeLedInfo.blue.duty = ucFlashCnt_or_Duty % 101;
    }
    if(usChannel & LED_BAG)
    {
        st_typeLedInfo.bag.state = enumStatus;
        st_typeLedInfo.bag.flashCnt = ucFlashCnt_or_Duty * 2 + 1;
        st_typeLedInfo.bag.flashFrequency = cFlashFrequency;
        st_typeLedInfo.bag.duty = ucFlashCnt_or_Duty % 101;
    }
    if(usChannel & LED_EXIST)
    {
        st_typeLedInfo.exist.state = enumStatus;
        st_typeLedInfo.exist.flashCnt = ucFlashCnt_or_Duty * 2 + 1;
        st_typeLedInfo.exist.flashFrequency = cFlashFrequency;
        st_typeLedInfo.exist.duty = ucFlashCnt_or_Duty % 101;
    }
}

/*
 * Return:      void
 * Parameters:  *ptypeLed: LED信息结构体
 * Description: LED状态刷新
 */
void vLedStateMachine(LedType *ptypeLed)
{
    switch(ptypeLed->state)
    {
        /* 关闭 */
        case LED_DISABLE:
            vLedClose(ptypeLed->channel);
            ptypeLed->state = LED_IDLE;
            break;

        /* 常亮 */
        case LED_ENABLE:
            vLedOpen(ptypeLed->channel);
            ptypeLed->state = LED_IDLE;
            break;

        /* 呼吸 */
        case LED_BREATHE:
            vLedDuty(ptypeLed->channel, ptypeLed->duty);
            break;

        /* 固定占空比 */
        case LED_DUTY:
            vLedDuty(ptypeLed->channel, st_sGrade * 0.01f);
            ptypeLed->state = LED_IDLE;
            break;

        /* 循环快闪 */
        case LED_FLASH_SLOW_CIRCULAR:
        /* 快闪后关闭 */
        case LED_FLASH_SLOW_DISABLE_CNT:
        /* 快闪后常亮 */
        case LED_FLASH_SLOW_ENABLE_CNT:

        /* 循环慢闪 */
        case LED_FLASH_FAST_CIRCULAR:
        /* 慢闪后关闭 */
        case LED_FLASH_FAST_DISABLE_CNT:
        /* 慢闪后常亮 */
        case LED_FLASH_FAST_ENABLE_CNT:
            if((st_uiLedTickCnt % ptypeLed->flashFrequency) == 0)
            {
                vLedRevesal(ptypeLed->channel);

                if((ptypeLed->state != LED_FLASH_SLOW_CIRCULAR) && (ptypeLed->state != LED_FLASH_FAST_CIRCULAR) && ((ptypeLed->flashCnt--) <= 0))
                {
                    ptypeLed->state = ((ptypeLed->state == LED_FLASH_SLOW_ENABLE_CNT) || (ptypeLed->state == LED_FLASH_FAST_ENABLE_CNT)) ? LED_ENABLE : LED_DISABLE;
                }
            }
            break;

        default : break;
    }
}

/*
 * Return:      void
 * Parameters:  void
 * Description: LED心跳计数 + 呼吸状态机
 */
static void vLedIncTick(void)
{
    /* 呼吸方向 */
    volatile static int8_t st_cDirection = 0;

    /* 所有LED使用同一个状态机变量，以方便实现一致的闪烁步调 */
    ++st_uiLedTickCnt;

    /* 更新呼吸模式占空比 */
    {
        st_sGrade += st_cDirection;
        /* 之所以把档位设置的比0小一些，是为了在呼吸状态时，LED能够彻底熄灭一段时间 */
        st_cDirection = (st_sGrade >= 100) ? -1 : ((st_sGrade <= -50) ? 1 : st_cDirection);
    }
}

void vLedMachine(void)
{
    LedType *ptypeLed = (LedType *)&st_typeLedInfo;
    int8_t i = 0, cLength = 0;

    vLedIncTick();

    /* 遍历全部 */
    cLength = sizeof(LedInfoType) / sizeof(LedType);
    while((cLength--) > 0)
    {
        vLedStateMachine(ptypeLed);
        ++ptypeLed;
    }
}

LedInfoType *ptypeLedGetInfo(void)
{
    return &st_typeLedInfo;
}
